package com.ming.mallchat.common.user.service.impl;

import cn.hutool.core.util.StrUtil;
import com.ming.mallchat.common.user.dao.UserDao;
import com.ming.mallchat.common.user.mapper.UserMapper;
import com.ming.mallchat.common.user.pojo.User;
import com.ming.mallchat.common.user.service.UserService;
import com.ming.mallchat.common.user.service.WXMsgService;
import com.ming.mallchat.common.user.service.adpater.UserAdapter;
import com.ming.mallchat.common.user.service.adpater.WxTextBuilder;
import com.ming.mallchat.common.websocket.domain.service.WebSocketService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.net.URLEncoder;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 86150
 * @date 2023/09/26
 */
@Service
@Slf4j
public class WXMsgServiceImpl implements WXMsgService {

    /**
     * openId和登入code的关系map
     */
    private static final ConcurrentHashMap<String, Integer> WAIT_AUTHOR_MAP = new ConcurrentHashMap<>();

    @Autowired
    private UserService userService;

    @Autowired
    private UserDao userDao;

    @Autowired
    private WebSocketService webSocketService;

    public static final String URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";

    @Value("${wx.mp.callback}")
    private String callback;

    /**
     * 扫码登入
     *
     * @param wxMpXmlMessage
     * @return {@link WxMpXmlOutMessage}
     */
    @Override
    public WxMpXmlOutMessage scan(WxMpXmlMessage wxMpXmlMessage, WxMpService wxMpService) {
        String openId = wxMpXmlMessage.getFromUser();
        Integer code = getEventKey(wxMpXmlMessage);
        if (Objects.isNull(code)) {
            return null;
        }
        User user = userDao.getbyOpenId(openId);
        boolean register = Objects.isNull(user);
        boolean authorized = StrUtil.isNotBlank(register ? "" : user.getAvatar());
        //用户已经登录并授权
        if (!register && authorized) {
            //走登录成功逻辑 通过code找到channel并推送消息
            webSocketService.scanLoginSuccess(code, user.getId());
        }
        //没有登录成功
        if (register) {
            user = UserAdapter.buildUserSave(openId);
            userService.register(user);
        }
        //推送链接让用户授权
        webSocketService.waitAuthor(code);
        WAIT_AUTHOR_MAP.put(openId, code);
        String authorUrl = String.format(URL, wxMpService.getWxMpConfigStorage().getAppId(), URLEncoder.encode(callback + "/callBack"));
        return WxTextBuilder.build("请点击登录：<a href=\"" + authorUrl + "\">登录</a>", wxMpXmlMessage);
    }

    /**
     * 用户授权成功
     *
     * @param userInfo 微信返回的用户信息
     */
    @Override
    public void author(WxOAuth2UserInfo userInfo) {
        String openid = userInfo.getOpenid();
        User user = userDao.getbyOpenId(openid);
        //更新用户信息
        //防止用户多次点击重复提交
        if (StrUtil.isBlank(user.getAvatar())) {
            fillUserInfo(user, userInfo);
        }
        //通过code获取channel做用户上线
        Integer code = WAIT_AUTHOR_MAP.remove(openid);
        webSocketService.scanLoginSuccess(code, user.getId());
    }

    private void fillUserInfo(User user, WxOAuth2UserInfo userInfo) {
        user = UserAdapter.buildAuthorUserSave(user, userInfo);
        userDao.updateById(user);
    }

    private Integer getEventKey(WxMpXmlMessage wxMpXmlMessage) {
        try {
            //扫码事件处理 事件码 qrscene_2
            String code = wxMpXmlMessage.getEventKey().replace("qrscene_", "");
            return Integer.valueOf(code);
        } catch (Exception e) {
            log.error("WXMsgServiceImpl getEventKey error:{}", wxMpXmlMessage.getEventKey(), e);
            return null;
        }
    }

}
